﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace XMLGener.Utils
{
    /// <summary>
    /// This class is used as util to work with xml nodes.
    /// </summary>
    public class XMLUtils
    {
        /// <summary>
        /// Function tries to find first child element which name is "tagName". 
        /// If element is not found, function tries to create child element whith name "tagName".
        /// Result is this found/created element.
        /// </summary>
        /// <param name="element">parent element of result</param>
        /// <param name="tagName">name of result element</param>
        /// <returns>found or created xml element</returns>
        public static XmlElement getOrCreateSubElement(XmlElement element, String tagName)
        {
            XmlElement result = getSubElement(element, tagName);
            if (result == null && element != null)
            {
                result = createSubElement(element, tagName);
            }
            return result;
        }

        /// <summary>
        /// Get first element of element "element"
        /// </summary>
        /// <param name="element">parent node</param>
        /// <param name="tagName">child name</param>
        /// <returns></returns>
        public static XmlElement getSubElement(XmlElement element, String tagName)
        {
            if (element == null)
                return null;
            return getSiblingOrThisElement(element.FirstChild, tagName);
        }

        /// <summary>
        ///  Get the element immidiately following element "element"
        /// </summary>
        /// <param name="element">siblink node</param>
        /// <param name="tagName">node name</param>
        /// <returns></returns>
        public static XmlElement getNextElement(XmlElement element, String tagName)
        {
            if (element == null)
                return null;
            return getSiblingOrThisElement(element.NextSibling, tagName);
        }


        /// <summary>
        /// Get the nearest (this or next) element in sibling 
        /// nodes from node "node"
        /// </summary>
        /// <param name="node">node</param>
        /// <param name="tagName">node name</param>
        /// <returns></returns>
        private static XmlElement getSiblingOrThisElement(XmlNode node, String tagName)
        {
            XmlNode n = node;
            while (n != null)
            {
                if (n.NodeType == XmlNodeType.Element && n.Name == tagName)
                {
                    return (XmlElement)n;
                }
                n = n.NextSibling;
            }
            return null;
        }

        /// <summary>
        /// Get the element immadiately following node "node"
        /// </summary>
        /// <param name="node">node</param>
        /// <returns></returns>
        public static XmlElement getNextElement(XmlNode node)
        {
            XmlNode n = node;
            while (n != null)
            {
                n = n.NextSibling;
                if (n != null && n.NodeType == XmlNodeType.Element)
                {
                    return (XmlElement)n;
                }
                
            }
            return null;
        }

        /// <summary>
        /// Get the element immadiately following node "node"
        /// </summary>
        /// <param name="node">node</param>
        /// <returns></returns>
        public static XmlElement getPrevoiusElement(XmlNode node)
        {
            XmlNode n = node;
            while (n != null)
            {
                n = n.PreviousSibling;
                if ( n != null && n.NodeType == XmlNodeType.Element)
                {
                    return (XmlElement)n;
                }
            }
            return null;
        }


        /// <summary>
        /// Get the element immadiately following node "node"
        /// </summary>
        /// <param name="node">node</param>
        /// <returns></returns>
        public static XmlElement getFirstSubElement(XmlNode node)
        {
            if (node == null)
                return null;
            XmlNode n = node.FirstChild;
            while (n != null)
            {
                if ( n.NodeType == XmlNodeType.Element)
                {
                    return (XmlElement)n;
                }
                n = n.NextSibling;
            }
            return null;
        }

        /// <summary>
        /// Create child element under "parent" element of name, where new element's name
        /// id "childName". Append this element to the end.
        /// </summary>
        /// <param name="parent">parement element</param>
        /// <param name="childName">new element's name</param>
        /// <returns>created element</returns>
        public static XmlElement createSubElement(XmlElement parent,string childName)
        {
            if (parent == null)
                return null;
            XmlElement newElement = parent.OwnerDocument.CreateElement(childName);
            parent.AppendChild(newElement);
            return newElement;
        }

        /// <summary>
        /// Create child elemetn under "parent" element of name, where new element's name
        /// id "childName". Insert this element as first elemetn in child elements.
        /// </summary>
        /// <param name="parent">parement element</param>
        /// <param name="childName">new element's name</param>
        /// <returns>created element</returns>
        public static XmlElement createFirstSubElement(XmlElement parent, string childName)
        {
            if (parent == null)
                return null;
            XmlElement newElement = parent.OwnerDocument.CreateElement(childName);
            parent.InsertBefore(getFirstSubElement(parent), newElement);
            return newElement;
        }


        /// <summary>
        /// Return decimal value of attribute "name" in elelemnt "elem"
        /// </summary>
        /// <param name="elem">element</param>
        /// <param name="name">attributes name</param>
        /// <returns>decimal value of attribute</returns>
        public static decimal getDecimalAttribute(XmlElement elem, string name)
        {
            if (elem == null || !elem.HasAttribute(name))
                return 0;
            decimal result = 0;
            try
            {
                result = Convert.ToDecimal(elem.GetAttribute(name));
            }
            catch (Exception)
            {
                return 0;
            }
            return result;
        }

        /// <summary>
        /// Return integer value of attribute "name" in elelemnt "elem"
        /// </summary>
        /// <param name="elem">element</param>
        /// <param name="name">attributes name</param>
        /// <returns>integer value of attribute</returns>
        public static int getIntAttribute(XmlElement elem, string name)
        {
            if (elem == null || !elem.HasAttribute(name))
                return 0;
            int result = 0;
            try
            {
                result = Convert.ToInt32(elem.GetAttribute(name));
            }
            catch (Exception)
            {
                return 0;
            }
            return result;
        }

        /// <summary>
        /// s
        /// </summary>
        /// <param name="elem"></param>
        /// <param name="name"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static string getAttribute(XmlElement elem,string name,string defValue)
        {
            if (elem == null)
                return defValue;
            if (!elem.HasAttribute(name))
            {
                return defValue;
            }
            return elem.GetAttribute(name);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="elem"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="logger"></param>
        public static void setAttribute(XmlElement elem, string name, string value, XLogger logger)
        {
            if (logger == null)
            {
                logger = XLogger.instance;
            }
            if (elem == null)
            {
                if (name == "name")
                    logger.addErrorLog(value, "Node has not defined xml element.");
                else
                    logger.addErrorLog("Setting attribute "+name, "Node has not defined xml element.");
                return;
            }
            if (name == null || name.Length < 1)
            {
                logger.addErrorLog(name, "Atribute's name is missing.");
                return;
            }

            elem.SetAttribute(name, value);


        }



    }
}
